import { BillCodeGenerator } from './../service/tool.service';
import {
  BillState,
  PurchaseBill,
  AuditorPurchaseQC,
  ApplierPurchaseQC,
  PurchaseItem,
} from './../entity/purchase.entity';
import {
  Body,
  Controller,
  Del,
  Get,
  Inject,
  Param,
  Post,
  Put,
} from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { In, Repository } from 'typeorm';
import { Context } from '@midwayjs/koa';
import { BillStateError, MissTargetError } from '../filter/error.filter';
@Controller('/purchase')
export class PurchaseController {
  @Post('/debug')
  async debug(@Body() purchaseBill: PurchaseBill) {
    console.log(purchaseBill);
    return 1;
  }
  @Post('/debugItem')
  async debugItem(@Body() purchaseItem: PurchaseItem) {
    console.log(purchaseItem);
    return 1;
  }
  @InjectEntityModel(PurchaseBill)
  repo: Repository<PurchaseBill>;
  @InjectEntityModel(PurchaseItem)
  itemRepo: Repository<PurchaseItem>;
  @Inject()
  ctx: Context;
  @Post('/query/applierPack')
  async query4ApplierPack(@Body() applierPurchaseQC: ApplierPurchaseQC) {
    const { pageNum, pageSize, minAmount, maxAmount, nameLike } =
      applierPurchaseQC;
    const pageStart = (pageNum - 1) * pageSize;
    // 查询条件 既有主表中的字段amount  又有子表中的字段goodsName
    // 需要分页 分页依据应该以主表为准 主表的一条等于业务中的一张 子表不是
    // 故而需要主表聚合/去重后 分页
    /* select pb.*
from PurchaseBill pb
         left join PurchaseItem pi
                   on pb.billId = pi.billFk 
where pi.goodsName like '%5%'
and pb.amount >1
group by pb.billId
order by pb.updateTime desc
limit 3,3;
     */
    // select  *  from  PurchaseBill pb
    // const pb =  new PurchaseBill() ,pb.items
    const builder = this.repo.createQueryBuilder('pb');
    // 只返回主表信息
    builder.leftJoin(PurchaseItem, 'pi', 'pb.billId = pi.billFk');
    // 返回主子表所有信息
    // builder.leftJoinAndMapMany("pb.items",PurchaseItem, 'pi', 'pb.billId = pi.billFk');
    if (nameLike) {
      builder.andWhere('pi.goodsName like :n ', { n: '%' + nameLike + '%' });
    }
    if (minAmount) {
      builder.andWhere('pb.amount >= :minAmount', { minAmount });
    }
    if (maxAmount) {
      builder.andWhere('pb.amount <= :maxAmount', { maxAmount });
    }
    builder.orderBy('pb.updateTime', 'DESC');
    // 以前单表分页 使用的是 limit =》 offset(pageStart) limit(pageSize)
    // builder.offset(pageStart).limit(pageSize)
    // 因为要聚合 去重 以主表为准 主表的一条对应业务的一张
    builder.skip(pageStart).take(pageSize);

    const r = await builder.printSql().getManyAndCount();
    // ['PB16869028418820014','PB16869028418820013']
    const result = r[0];
    const ids = result.map(e => e.billId);
    console.log('ids: ', ids);

    // select from PurchaseItem pi where pi.billFk in('PB16867280668870007',
    //  'PB16867280148510005)',
    const itemsAll = await this.itemRepo.findBy({
      billFk: In(ids),
    });
    console.log('itemsAll: ', itemsAll);
    itemsAll.forEach(pi => {
      let g = result.find(pb => pb.billId === pi.billFk);
      // let g = result.find(pb => {
      //  return  pb.billId === pi.billFk;
      // });
      // console.log('xxxxx', g);
      if (g) {
        g.items.push(pi);
      }
    });

    console.log(r);

    return {
      results: r[0],
      total: r[1],
    };
  }
  /* 负责 条件筛选 分页 排序 目的是获取ids
  select  pb.*  from PurchaseBill pb
left join PurchaseItem pi
on pb.billId = pi.billFk
where pi.goodsName like '%5%'
group by pb.billId
order by pb.updateTime
limit 3,3
// 根据ids查出所有表单信息
# ids ['PB16869028418820014','PB16867280668870007','PB16867281099150008']
select * from PurchaseBill pb
left join PurchaseItem pi
on pb.billId = pi.billFk 
where billId in ('PB16869028418820014','PB16867280668870007','PB16867281099150008') */
  @Post('/query/applier')
  async query4Applier(@Body() applierPurchaseQC: ApplierPurchaseQC) {
    const { pageNum, pageSize, minAmount, maxAmount, nameLike } =
      applierPurchaseQC;
    const pageStart = (pageNum - 1) * pageSize;
    const builder1 = this.repo.createQueryBuilder('pb');
    /* left join PurchaseItem pi on pb.billId = pi.billFk */
    builder1.leftJoin(PurchaseItem, 'pi', 'pb.billId = pi.billFk');

    // 获取当前登录人信息 只查询该登录人相关的采购单
    const currentUser = this.ctx.getAttr('username');
    // 静态条件
    builder1.andWhere('pb.applier = :a', { a: currentUser });
    // where 子句 动态查询
    if (nameLike) {
      builder1.andWhere('pi.goodsName like :n ', { n: '%' + nameLike + '%' });
    }
    if (minAmount) {
      builder1.andWhere('pb.amount >= :minAmount', { minAmount });
    }
    if (maxAmount) {
      builder1.andWhere('pb.amount <= :maxAmount', { maxAmount });
    }
    // group by pb.billId 去重
    builder1.groupBy('pb.billId');
    // order by pb.updateTime
    builder1.orderBy('pb.updateTime', 'DESC');
    // limit 3,3
    builder1.offset(pageStart).limit(pageSize);

    const r1 = await builder1.printSql().getManyAndCount();
    console.log(r1[0]);
    // ids = ['PB16869028418820014','PB16867280668870007','PB16867281099150008']
    const ids = r1[0].map(pb => pb.billId);
    console.log(ids);
    if (ids.length === 0) {
      return {
        results: [],
        total: 0,
      };
    }
    // 开启第二条sql语句
    const builder2 = this.repo.createQueryBuilder('pb');
    builder2.leftJoinAndMapMany(
      'pb.items',
      PurchaseItem,
      'pi',
      'pb.billId = pi.billFk'
    );
    builder2.where('billId in ( :...ids )', { ids: ids });
    builder2.orderBy('pb.updateTime', 'DESC');
    const r2 = await builder2.getMany();
    // r2.sort((a, b) => {
    //   return b.updateTime.getTime() - a.updateTime.getTime();
    // });
    console.log('r2', r2);
    return {
      // results 从r1[0] 换成r2
      results: r2,
      total: r1[1],
    };
  }
  @Inject()
  billCodeGenerator: BillCodeGenerator;
  // 单增一张采购单=  单增一条主表信息pb + 增加n条子表信息
  @Post('/insert')
  async insert(@Body() purchaseBill: PurchaseBill) {
    const pb = new PurchaseBill();
    pb.billState = BillState.toSubmit;

    pb.billId = await this.billCodeGenerator.nextCode('PB');
    // 信任前端传递 的属性 supplier供货单位	orderDate订购日期	receiveDate交货日期
    pb.supplier = purchaseBill.supplier;
    pb.orderDate = purchaseBill.orderDate;
    pb.receiveDate = purchaseBill.receiveDate;

    let amount = 0;
    purchaseBill.items.forEach((item: PurchaseItem, index: number) => {
      item.billFk = pb.billId;
      item.itemId = index;
      item.priority = index;
      amount = amount + item.price * item.quantity;
    });
    pb.amount = amount;
    pb.nextItemId = purchaseBill.items.length;

    pb.items = purchaseBill.items;
    pb.applier = this.ctx.getAttr('username');

    pb.updateTime = new Date();
    console.log('待存储的整张单据', pb);
    await this.repo.save(pb);
    await this.itemRepo.save(pb.items);
    // this.repo.save(pb.items)
    return pb;
  }
  @Get('/find/:billId')
  async findByBillId(@Param('billId') billId: string) {
    const r = await this.repo
      .createQueryBuilder('pb')
      .leftJoinAndMapMany(
        'pb.items',
        PurchaseItem,
        'pi',
        'pb.billId = pi.billFk'
      )
      .where('pb.billId = :i', { i: billId })
      .getOne();
    if (!r) {
      throw new MissTargetError('待查询的购物单不存在');
    }
    return r;
  }
  @Get('/find2/:billId')
  async findByBillId2(@Param('billId') billId: string) {
    const pb = await this.repo.findOneBy({
      billId: billId,
    });
    // console.log(pb);
    if (!pb) {
      throw new MissTargetError('待查询的购物单不存在');
    }
    const items = await this.itemRepo.findBy({
      billFk: billId,
    });
    pb.items = items;
    return pb;
  }
  @Del('/remove/:billId')
  async removeByBillId(@Param('billId') billId: string) {
    const pb = await this.repo.findOneBy({
      billId: billId,
    });
    // console.log(pb);
    if (!pb) {
      throw new MissTargetError('待删除的购物单不存在');
    }
    // 可以补充 必须是待提交状态才可以删除废弃
    if (pb.billState !== BillState.toSubmit) {
      throw new BillStateError('已提交或已审核的购物不能删除');
    }
    // 没有强外键约束，主子表新增删除顺序无所谓
    await this.itemRepo.delete({
      billFk: billId,
    });
    await this.repo.remove(pb);
    return billId;
  }
  // 整体修改 主表信息+子表信息
  @Put('/modify')
  async modify(@Body() purchaseBill: PurchaseBill) {
    // this.repo.save(purchaseBill)
    const billId = purchaseBill.billId;
    const pb = await this.repo.findOneBy({
      billId: billId,
    });
    if (!pb) {
      throw new MissTargetError('待修改的购物单未找到');
    }
    if (pb.billState !== BillState.toSubmit) {
      throw new BillStateError('只有未提交状态才能修改');
    }
    pb.billState = BillState.toSubmit;
    // supplier供货单位	orderDate订购日期	receiveDate交货日期

    pb.supplier = purchaseBill.supplier;
    pb.orderDate = purchaseBill.orderDate;
    pb.receiveDate = purchaseBill.receiveDate;

    let amount = 0;
    purchaseBill.items.forEach((item: PurchaseItem, index: number) => {
      item.billFk = billId;
      item.itemId = index;
      item.priority = index;
      amount += item.price * item.quantity;
    });
    pb.amount = amount;
    pb.nextItemId = purchaseBill.items.length;
    pb.items = purchaseBill.items;

    pb.applier = this.ctx.getAttr('username');
    pb.updateTime = new Date();
    // console.log(pb);
    await this.repo.save(pb);
    // 对于子表 先清空 在追加 适合条目数小于10的时候
    await this.itemRepo.delete({
      billFk: billId,
    });
    await this.itemRepo.save(pb.items);
    return pb;
    // this.itemsRep.deleteByBillId
    // this.repo.save(pb)
    // this.itemRepo.save(items)
  }

  // 部分修改 :todo
  // 提交 审核 重交 三者 跟子表完全无关
  @Put('/submit')
  async submit(@Body() purchaseBill: PurchaseBill) {
    const auditor = purchaseBill.auditor;
    console.log(' 购物单 要提交给 它审核： ' + auditor);
    const billId = purchaseBill.billId;
    const pb = await this.repo.findOneBy({
      billId: billId,
    });
    if (!pb) {
      throw new MissTargetError('待提交的数据不存在');
    }
    if (pb.billState !== BillState.toSubmit) {
      throw new BillStateError('已提交或已审核的单据不能重复提交');
    }
    pb.billState = BillState.toAudit;

    pb.auditor = auditor;
    pb.applyTime = new Date();
    pb.updateTime = new Date();
    await this.repo.save(pb);
    return pb.billId;
  }
  /* 
select * from PurchaseBill pb
where pb.supplier like '%实%'
  and pb.billState = 'toAudit'
and pb.auditor = 'swagger'
order by pb.updateTime desc
limit 0,3 */
  @Post('/query/auditor')
  async query4Auditor(@Body() auditorPurchaseQC: AuditorPurchaseQC) {
    const { pageNum, pageSize, billState, supplierLike } = auditorPurchaseQC;
    const pageStart = (pageNum - 1) * pageSize;
    const builder1 = this.repo.createQueryBuilder('pb');
    // 静态条件
    const user = this.ctx.getAttr('username');
    builder1.andWhere(' pb.auditor = :user', { user });
    // 动态条件
    if (billState) {
      builder1.andWhere('pb.billState = :bs', { bs: billState });
    }
    if (supplierLike) {
      builder1.andWhere('pb.supplier like :s', { s: '%' + supplierLike + '%' });
    }
    // 分页排序
    builder1.orderBy('pb.updateTime', 'DESC');
    builder1.offset(pageStart).limit(pageSize);
    const r = await builder1.printSql().getManyAndCount();
    console.log(r);
    // ['PB16874912890130034', 'PB168749128901300"]
    const ids = r[0].map(e => {
      return e.billId;
    });
    if (ids.length === 0) {
      return {
        results: [],
        total: 0,
      };
    }
    // 开启第二条sql
    const builder2 = this.repo.createQueryBuilder('pb');
    /* 
    select pb.* from PurchaseBill pb
left join  PurchaseItem pi
on pb.billId = pi.billFk
where pb.billId in ('PB16867280148510005','PB16867281099150008')
 */
    builder2.leftJoinAndMapMany(
      'pb.items',
      PurchaseItem,
      'pi',
      'pb.billId = pi.billFk'
    );
    builder2.where('pb.billId in ( :...ids )', { ids });
    builder2.orderBy('pb.updateTime', 'DESC');
    const rr = await builder2.getMany();
    return {
      results: rr,
      total: r[1],
    };
  }
  @Put('/audit')
  async audit(@Body() purchaseBill: PurchaseBill) {
    // 解构赋值
    // const billId = purchaseBill.billId;
    // const auditMsg = purchaseBill.auditMsg;
    const { billId, auditMsg } = purchaseBill;
    const pb = await this.repo.findOneBy({
      billId: billId,
    });
    if (!pb) {
      throw new MissTargetError('待审核的数据不存在');
    }
    if (pb.billState !== BillState.toAudit) {
      throw new BillStateError('只有待审核状态的表单才能审核');
    }
    pb.billState = BillState.auditted;
    // 记录历史信息 注意字段量255
    if (pb.auditMsg) {
      pb.history = pb.auditTime.getTime() + ':' + pb.auditMsg + ',' + pb.history;
    }
    // 状态改变后的后置操作
    pb.auditMsg = auditMsg;
    pb.auditTime = new Date();
    pb.updateTime = new Date();

    await this.repo.save(pb);
    return pb;
  }
  // 打回重交
  @Put('/resent')
  async resent(@Body() purchaseBill: PurchaseBill) {
    const { billId, auditMsg } = purchaseBill;
    const pb = await this.repo.findOneBy({
      billId: billId,
    });
    if (!pb) {
      throw new MissTargetError('待审核的数据不存在');
    }
    if (pb.billState !== BillState.toAudit) {
      throw new BillStateError('只有待审核状态才可以打回重交');
    }
    pb.billState = BillState.toSubmit;
    // 后置操作
    if (pb.auditMsg) {
      pb.history = pb.auditTime.getTime() + ':' + pb.auditMsg + ',' + pb.history;
    }
    pb.auditMsg = auditMsg;
    pb.auditTime = new Date();
    pb.updateTime = new Date();

    await this.repo.save(pb);
    return pb;
  }
}
